package upload

import (
	"bytes"
	"crypto/md5"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"gitee.com/alex_li/zangjingge/internal/oss"
	"gitee.com/alex_li/zangjingge/internal/tools"
	"github.com/lishimeng/app-starter"
	"github.com/lishimeng/app-starter/server"
	"github.com/lishimeng/go-log"
	"io"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"time"
)

// 上传文件到缓存区

type TmpFileResponse struct {
	FileId  string `json:"fileId"`
	Name    string `json:"fileName"`
	Success bool   `json:"success"`
}

type TmpUploadResponse struct {
	app.Response
	TmpFileResponse
}

func uploadTemp(ctx server.Context) {
	log.Info("start upload...")
	var resp TmpUploadResponse
	meta, err := saveTempFile(ctx)
	if err != nil {
		log.Info(err)
		resp.Code = http.StatusInternalServerError
		return
	}

	resp.Code = 200
	resp.Name = meta.FileName
	resp.FileId = meta.Id
	resp.TmpFileResponse.Success = true
	ctx.Json(resp)
}

func saveTempFile(ctx server.Context) (meta oss.TempFileMeta, err error) {
	now := time.Now()
	file, info, err := ctx.C.FormFile("file")
	if err != nil {
		log.Debug(err)
		return
	}
	defer func() {
		_ = file.Close()
	}()

	uploadName := info.Filename
	ext := filepath.Ext(uploadName)

	log.Info("info.Filename %s", info.Filename)
	// temp namespace
	saveName := tools.GenMd5Code(fmt.Sprintf("%s%d", uploadName, now.Unix()))
	namespace := saveName // 用相同的数值
	namespaceFolder := path.Join(oss.GetTempRootFolder(), namespace)
	err = os.MkdirAll(namespaceFolder, os.ModePerm)
	if err != nil {
		log.Info("create temp dir fail: %d", namespaceFolder)
		log.Info(err)
		return
	}

	dest := path.Join(namespaceFolder, saveName)
	out, err := os.OpenFile(dest,
		os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Debug(err)
		return
	}
	defer func() {
		_ = out.Close()
	}()

	size, digestMd5, digestSha256, err := fileCopy(out, file)
	if err != nil {
		log.Debug(err)
		return
	}

	log.Debug("upload file:%s -> %s[%d]", uploadName, dest, size)
	meta = oss.TempFileMeta{
		Md5:       fmt.Sprintf("%02x", digestMd5),
		Sha256:    fmt.Sprintf("%02x", digestSha256),
		Id:        saveName,
		Ext:       ext,
		FileName:  uploadName,
		FileSize:  size,
		Timestamp: now.Unix(),
	}
	bs, err := json.Marshal(meta)
	if err != nil {
		log.Debug(err)
		return
	}
	metaFile := oss.GetMetaFilePath(namespaceFolder)
	f, err := os.OpenFile(metaFile, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		log.Debug(err)
		return
	}
	_, err = io.Copy(f, bytes.NewReader(bs))
	return
}

func fileCopy(des io.Writer, src io.Reader) (size int64, md5Digest, sha256Digest []byte, err error) {

	buf := make([]byte, 1024)
	md5Handler := md5.New()
	sha256Handler := sha256.New()
	var n = 0
	for {
		n, err = src.Read(buf)
		if err != nil {
			if err == io.EOF {
				err = nil
			}
			break
		}
		n, err = io.WriteString(md5Handler, string(buf[:n]))
		if err != nil {
			break
		}
		n, err = io.WriteString(sha256Handler, string(buf[:n]))
		if err != nil {
			break
		}
		n, err = des.Write(buf[:n])
		if err != nil {
			break
		}
		size += int64(n)
	}
	md5Digest = md5Handler.Sum(nil)
	sha256Digest = sha256Handler.Sum(nil)
	return
}
